package memList

import (
	webs2cmsg "WebSvr/ProtoMessage/S2CMsg"
	"WebSvr/modules/common"
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/golang/protobuf/proto"
)

type serverStatus struct {
	msglogic2Web *common.OnlineUserReport
	status       int32
	recvTime     int64 //接收到时候的时间戳
	serverIp     string
	areaName     string
	bnewArea     uint8 //是否新区
	port         int64
}

type MemListMgr struct {
	checkcycle int64                   //web服务器定时检查掉线周期，秒为单位
	mapMsgInfo map[string]serverStatus //key:ServerName
	maxAfford  int64                   //服务器最大负载人数
	Lock       sync.RWMutex
}

var gMemListMgr *MemListMgr

func NewMemListMgr(cfgcycle int64, maxAfford int64) {
	gMemListMgr = &MemListMgr{
		checkcycle: cfgcycle,
		mapMsgInfo: make(map[string]serverStatus),
		maxAfford:  maxAfford,
	}
}

func GetMemListMgr() *MemListMgr {
	return gMemListMgr
}

func (self *MemListMgr) Add2serverListMap(serverIP string, port int64, areaName string, bnewArea uint8, pMsg *common.OnlineUserReport, recvTimeStamp int64) {
	self.Lock.Lock()
	defer self.Lock.Unlock()
	serverName := pMsg.ServerName
	var serverInfo serverStatus
	serverInfo.serverIp = serverIP
	serverInfo.msglogic2Web = pMsg
	if pMsg.OnlineNums >= uint32(self.maxAfford*3/4) {
		serverInfo.status = common.SERVER_BUSY
	} else {
		serverInfo.status = common.SERVER_NORMAL
	}
	serverInfo.port = port
	serverInfo.recvTime = time.Now().Unix()
	serverInfo.areaName = areaName
	serverInfo.bnewArea = bnewArea
	self.mapMsgInfo[serverName] = serverInfo

}

func (self *MemListMgr) checkServerStatus() {
	self.Lock.Lock()
	defer self.Lock.Unlock()
	for name, serverInfo := range self.mapMsgInfo {
		curTime := time.Now().Unix()
		period := serverInfo.msglogic2Web.Cycle * 2
		if curTime-serverInfo.recvTime > int64(period) {
			serverInfo.status = common.SERVER_OFFLINE
			self.mapMsgInfo[name] = serverInfo
		}
	}

}

func (self *MemListMgr) OnTimer() {

	timer := time.NewTicker(time.Duration(self.checkcycle) * time.Second)
	for {
		select {
		case <-timer.C:
			//时间到，检查map中是否有过期的
			if common.DebugCtrl == 0 {
				self.checkServerStatus()
			}

		}
	}
}

//发送给客户端所有服务器列表
func (self *MemListMgr) GetServerList() (strData string, err error) {
	self.Lock.RLock()
	defer self.Lock.RUnlock()
	msgS2CServerList := &webs2cmsg.ServerListS2C{}
	listLen := len(self.mapMsgInfo)
	if listLen == 0 {
		msgS2CServerList.Info = nil
		msgS2CServerList.Errcode = webs2cmsg.ErrorCode_FAIL_ERRCODE.Enum()
		return "", errors.New("online server list is empty!")
	}
	var rowNum int64 = 1
	msgS2CServerList.Errcode = webs2cmsg.ErrorCode_OK_ERRCODE.Enum()
	for name, serverInfo := range self.mapMsgInfo {
		msgS2CServerInfo := &webs2cmsg.ServerInfo{}
		msgS2CServerInfo.RowNum = proto.Int64(rowNum)
		rowNum++
		msgS2CServerInfo.ServerName = proto.String(name)
		msgS2CServerInfo.ServerIP = proto.String(serverInfo.serverIp)
		msgS2CServerInfo.Port = proto.Int64(serverInfo.port)
		msgS2CServerInfo.OnlineNums = proto.Int64(int64(serverInfo.msglogic2Web.OnlineNums))
		msgS2CServerInfo.MaxOnLineNums = proto.Int64(int64(serverInfo.msglogic2Web.MaxOnLineNums))
		msgS2CServerInfo.MaxAffordNum = proto.Int64(int64(self.maxAfford))

		if serverInfo.bnewArea == common.AREA_NORMAL {
			msgS2CServerInfo.NewArea = webs2cmsg.AreaStatus_AREA_NORMAL.Enum()
		} else if serverInfo.bnewArea == common.AREA_NEW {
			msgS2CServerInfo.NewArea = webs2cmsg.AreaStatus_AREA_NEW.Enum()
		} else {
			msgS2CServerList.Errcode = webs2cmsg.ErrorCode_FAIL_ERRCODE.Enum()
			return "", errors.New("serverInfo.bnewArea invalid!")
		}

		if serverInfo.areaName == "" {
			msgS2CServerList.Errcode = webs2cmsg.ErrorCode_FAIL_ERRCODE.Enum()
		}
		msgS2CServerInfo.AreaName = proto.String(serverInfo.areaName)

		switch serverInfo.status {
		case common.SERVER_BUSY:
			{
				msgS2CServerInfo.Status = webs2cmsg.ServerStatus_SERVER_BUSY.Enum()
			}
		case common.SERVER_OFFLINE:
			{
				msgS2CServerInfo.Status = webs2cmsg.ServerStatus_SERVER_OFFLINE.Enum()
			}
		case common.SERVER_NORMAL:
			{
				msgS2CServerInfo.Status = webs2cmsg.ServerStatus_SERVER_NORMAL.Enum()
			}

		}
		msgS2CServerList.Info = append(msgS2CServerList.Info, msgS2CServerInfo)

	}
	fmt.Println(msgS2CServerList)
	// 进行编码
	datalist, err := proto.Marshal(msgS2CServerList)
	if err != nil {
		msgS2CServerList.Errcode = webs2cmsg.ErrorCode_FAIL_ERRCODE.Enum()
		return "", err
	}
	strData = string(datalist)

	return strData, nil
}
